﻿using System;
using System.IO;
using CID.Execution.Support.Information;

namespace CID.Execution.Support.PackageHandling
{
    public abstract class FileSystemBasedPackageHandlerBase<TPackageHandlingToken> : IPackageHandler
        where TPackageHandlingToken : FileSystemBasedPackageHandlingToken
    {
        public IPackageHandlingToken PrepareForUsage(PackageInfo packageInfo)
        {
            try
            {
                var tempPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
                var packagePath = Path.Combine(tempPath, Path.GetRandomFileName());

                var packageHandlingToken = CreatePackageHandlingToken(tempPath, packagePath);
                CreateTempFolderAndSavePackage(packageInfo, packageHandlingToken);
                InternalPrepareForUsage(packageInfo, packageHandlingToken);

                return packageHandlingToken;
            }
            catch (Exception ex)
            {
                throw new PackageHandlingException(ex);
            }
        }

        public void Release(IPackageHandlingToken packageHandlingToken)
        {
            if (!(packageHandlingToken is TPackageHandlingToken)) 
                throw new InvalidCastException(String.Format("{0} is not a valid instance of {1}", packageHandlingToken, typeof(TPackageHandlingToken)));

            InternalRelease(packageHandlingToken as TPackageHandlingToken);
            RemoveTempFolderAndDeletePackage(packageHandlingToken as TPackageHandlingToken);
        }

        private void CreateTempFolderAndSavePackage(PackageInfo packageInfo, TPackageHandlingToken packageHandlingToken)
        {
            Directory.CreateDirectory(packageHandlingToken.TempPath);
            File.WriteAllBytes(packageHandlingToken.OriginalPackagePath, packageInfo.Content);
        }

        private void RemoveTempFolderAndDeletePackage(TPackageHandlingToken packageHandlingToken)
        {
            File.Delete(packageHandlingToken.OriginalPackagePath);
            Directory.Delete(packageHandlingToken.TempPath, true);
        }

        protected abstract TPackageHandlingToken CreatePackageHandlingToken(string tempPath, string packagePath);

        protected abstract void InternalPrepareForUsage(PackageInfo packageInfo, TPackageHandlingToken packageHandlingToken);

        protected abstract void InternalRelease(TPackageHandlingToken packageHandlingToken);
    }
}
